package com.ruoyi.common.utils.excel;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.ruoyi.common.exception.ServiceException;
import org.springframework.web.multipart.MultipartFile;

import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

public class ExcelClient<T> {

    private static final int SHEET_NO = 0;


    public static void writeFile(List list,String fileName,Class clazz) throws IOException {
        EasyExcel.write(fileName,clazz).sheet(fileName).doWrite(list);
    }

    /**
     * 导出 , 直接导出excel方式
     * @param fileName
     * @param clazz
     * @param list
     * @param response
     */
    public static void outputExcel(String fileName, Class clazz, List list, HttpServletResponse response) {
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            String sheetName = fileName;
            fileName = URLEncoder.encode(fileName, "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), clazz).sheet(sheetName).doWrite(list);
        } catch (Exception var5) {
            throw new ServiceException("output excel fail," + var5.getMessage());
        }
    }


    /**
     *
     * @param file 导入文件
     * @param clazz 导入的实体类
     * @param headRowNumber 表头
     * @return 数组对象
     * @throws Exception
     */
    public static List readFile(MultipartFile file, Class clazz, int headRowNumber, AnalysisEventListener listener) throws Exception{
        checkFile(file);
        /* 开始读Excel，返回一个List<T>集合，继续后续入库操作 */
        return readStream(file.getInputStream(),clazz,headRowNumber,listener);
    }


    public static List readStream(InputStream inputStream,Class clazz, int headRowNumber, AnalysisEventListener listener) throws Exception{
        /* 调用read方法 */
        return EasyExcel.read(inputStream,listener)
                /*对应导入的实体类*/
                .head(clazz)
                /*导入数据的sheet页编号，0代表第一个sheet页，如果不填，则会导入所有sheet页的数据*/
                .sheet(SHEET_NO)
                /*列表头行数，1代表列表头有1行，第二行开始为数据行*/
                .headRowNumber(headRowNumber)
                /*开始读Excel，返回一个List<T>集合，继续后续入库操作*/
                .doReadSync();
    }


    public static void checkFile(MultipartFile file) throws IOException {
        // 1. 判断文件是否为空
        if (ObjectUtil.isNull(file) || file.isEmpty()) {
            throw new IllegalArgumentException("上传的文件不能为空");
        }

        // 2. 获取文件的原始名称，用于后续的异常提示信息
        String originalFilename = file.getOriginalFilename();
        if(StrUtil.isEmpty(originalFilename)) {
            throw new IllegalArgumentException("上传的文件名不能为空");
        }

        // 3. 判断文件扩展名是否为 .xls 或 .xlsx，初步确认是否可能是 Excel 文件
        boolean isExcel = originalFilename.toLowerCase().matches("^.+\\.(xls|xlsx)$");
        if (!isExcel) {
            throw new IllegalArgumentException("上传的文件必须为 Excel 格式 (.xls 或 .xlsx)");
        }

        // 4. 尝试用 Apache POI 的 WorkbookFactory 打开文件，进一步确认是否为合法的 Excel 文件
        /*try {
            Workbook workbook = WorkbookFactory.create(file.getInputStream());
            workbook.close(); // 关闭工作簿以释放资源，但不关闭输入流
        } catch (Exception e) {
            throw new IllegalArgumentException("上传的文件 '" + originalFilename + "' 不是有效的 Excel 文件", e);
        }*/

    }


    /**
     * 创建数据
     * @param rowData
     * @return
     */
    public static List<List> convertToData(List... rowData){
        return new ArrayList<>(Arrays.asList(rowData));
    }

    /**
     * 创建表头
     * @param headData
     * @return
     */
    @SafeVarargs
    public static List<List<List<String>>> convertToHead(List<String>... headData){
        List<List<List<String>>> headList = new ArrayList<>();
        for (List<String> list : headData) {
            List<List<String>> head = convert(list);
            headList.add(head);
        }
        return headList;
    }

    private static List<List<String>> convert(List<String> headData){
        return headData.stream().map(Arrays::asList).collect(Collectors.toList());
    }


    /**
     * 创建动态excel文件,动态多行表头,多sheet,带数据
     * @param headMap , KV模式 , K是sheet名称,V是表头(可多个) ， 使用 convertToHead 方法
     * @param dataMap , KV模式 , K是sheet名称,V是数据 ， 使用 convertToData 方法
     * @param fileName excel文件名称
     * @param response
     * @throws Exception
     *
     * 使用案例
     *         List<String> list01 = Arrays.asList("产品编码", "产品名称", "产品数量", "动态字段1", "动态字段2", "动态字段3");
     *         List<String> list02 = Arrays.asList("经销商编码", "经销商名称", "产品数量", "动态字段1", "动态字段2", "动态字段3");
     *         List<List<List<String>>> lists01 = convertToHead(list01,list02);
     *
     *         List<String> list03 = Arrays.asList("经销商编码", "经销商名称");
     *         List<List<List<String>>> lists03 = convertToHead(list03);
     *
     *         LinkedHashMap<String, List<List<List<String>>>> headMap = new LinkedHashMap<>();
     *         headMap.put("第一个sheet",lists01);
     *         headMap.put("第二个sheet",lists03);
     *
     *         List<List> listData201 = convertToData(list03,list03,list03);
     *         Map<String, List<List>> dataMap = new HashMap<>();
     *         dataMap.put("第二个sheet",listData201);
     *
     *         createDynamicExcel(headMap,dataMap,"动态excel",response);
     */
    public static void createDynamicExcel(LinkedHashMap<String,List<List<List<String>>>> headMap,
                                          Map<String,List<List>> dataMap,
                                          String fileName,
                                          HttpServletResponse response) throws Exception {
        if(CollUtil.isEmpty(headMap)){
            return;
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName+".xlsx", "UTF-8"));

        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();

        int sheetIndex = 0;
        for (Map.Entry<String, List<List<List<String>>>> map : headMap.entrySet()) {
            String key = map.getKey();
            List<List<List<String>>> headRows = map.getValue();

            WriteSheet sheet = EasyExcel.writerSheet(sheetIndex, key).build();
            int headRowSize = headRows.size();
            for (int i = 0; i < headRows.size(); i++) {
                //创建表格并写入表头
                WriteTable table = EasyExcel.writerTable(i).needHead(Boolean.TRUE).build();
                table.setHead(headRows.get(i));

                if (i == headRowSize-1) {
                    excelWriter.write(getData(dataMap,key)  , sheet , table);
                }else {
                    excelWriter.write(Collections.emptyList()  , sheet , table);
                }
            }
            sheetIndex++;
        }
        excelWriter.finish();
        response.flushBuffer();
    }

    private static List<List> getData(Map<String,List<List>> dataMap,String dataKsy){
        if(CollUtil.isNotEmpty(dataMap) && CollUtil.isNotEmpty(dataMap.get(dataKsy))){
            return dataMap.get(dataKsy);
        }
        return Collections.emptyList();
    }



}

